package images

import (
	"bytes"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"os"

	"github.com/corona10/goimagehash"
)

// Decode 图片解码.
func Decode(file string) (image.Image, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return png.Decode(f)
}

// DecodeBytes 字节转换图片.
func DecodeBytes(bs []byte) (image.Image, error) {
	return png.Decode(bytes.NewReader(bs))
}

// SubImage 局部.
func SubImage(img image.Image, r image.Rectangle) (image.Image, error) {
	switch i := img.(type) {
	case *image.NRGBA:
		return i.SubImage(r), nil
	case *image.RGBA:
		return i.SubImage(r), nil
	case *image.RGBA64:
		return i.SubImage(r), nil
	case *image.NRGBA64:
		return i.SubImage(r), nil
	case *image.Gray:
		return i.SubImage(r), nil
	case *image.Gray16:
		return i.SubImage(r), nil
	default:
		return nil, ErrorType
	}
}

// Distance 图片距离.
func Distance(a image.Image, b image.Image) (int, error) {
	h1, err := goimagehash.DifferenceHash(a)
	if err != nil {
		return 0, err
	}

	h2, err := goimagehash.DifferenceHash(b)
	if err != nil {
		return 0, err
	}

	return h1.Distance(h2)
}

// Rect 绘制矩形.
func Rect(img draw.Image, r image.Rectangle, c color.Color) {
	size := 2
	draw.Draw(img, image.Rect(r.Min.X, r.Min.Y-size, r.Max.X, r.Min.Y), &image.Uniform{c}, image.Point{}, draw.Src)
	draw.Draw(img, image.Rect(r.Min.X, r.Max.Y, r.Max.X, r.Max.Y+size), &image.Uniform{c}, image.Point{}, draw.Src)
	draw.Draw(img, image.Rect(r.Min.X-size, r.Min.Y, r.Min.X, r.Max.Y), &image.Uniform{c}, image.Point{}, draw.Src)
	draw.Draw(img, image.Rect(r.Max.X, r.Min.Y, r.Max.X+size, r.Max.Y), &image.Uniform{c}, image.Point{}, draw.Src)
}

// Save 保存图片.
func Save(img image.Image, file string) error {
	f, err := os.Create(file)
	if err != nil {
		return err
	}
	defer f.Close()

	return png.Encode(f, img)
}

// Abs 绝对值.
func Abs(i int) int {
	if i < 0 {
		return i * -1
	}

	return i
}

// ToGray 转换成灰度.
func ToGray(img image.Image) image.Image {
	bounds := img.Bounds()
	gray := image.NewGray(bounds)

	for x := 0; x < bounds.Max.X; x++ {
		for y := 0; y < bounds.Max.Y; y++ {
			gray.Set(x, y, img.At(x, y))
		}
	}

	return gray
}
